import { Logger } from '../logger';
import { runErrorMapped } from './errorWrapper';

const SAVE_CPU_THRESHOLD = 100;

let cachedMemory = undefined;

const cpuUsageTrack = [];

/**
 * warn! 启用后，将使用一些奇技淫巧缓存 Memory 对象以减少 CPU 消耗，
 * warn! 但是可能会出一些预料之外的问题。请谨慎使用。
 */
const CACHE_MEMORY = false;

export class BotWrapper {

    private static cacheMemory() {
        if (!CACHE_MEMORY) {    // 不启用缓存
            return;
        }
        if (cachedMemory) {
            // 已经缓存了 Memory 对象，清除全局默认的 lazy-load Memory
            // @ts-ignore
            delete global.Memory;
            // @ts-ignore
            global.Memory = cachedMemory;
            // @ts-ignore
            RawMemory._parsed = global.Memory;
        }
        else {
            // @ts-ignore
            cachedMemory = global.Memory;
        }
    }

    static wrapLoop(loop: () => void) {
        return function () {
            // 缓存 Memory
            BotWrapper.cacheMemory();
            // 检查是否在战争状态
            if (!settings.warTime) {
                // 如果不在打仗，在 CPU 不够时屯一点 CPU
                if (Game.cpu.bucket <= SAVE_CPU_THRESHOLD && settings.saveBucket) {
                    Logger.info(`CPU bucket 不足，暂停执行 (目前余量 ${Game.cpu.bucket})`, 'BOT');
                    return;
                }
            }
            runErrorMapped(() => {
                // 执行 loop
                const begin = Game.cpu.getUsed();
                loop();
                const used = Game.cpu.getUsed() - begin;
                // 执行时间检查
                if (used > Game.cpu.limit + 1) {
                    Logger.warn(`CPU 使用超出限额：使用了 ${used}ms`, 'BOT');
                }
                // 加入 CPU 使用记录
                if (cpuUsageTrack.length > 20) {
                    cpuUsageTrack.shift();
                }
                cpuUsageTrack.push(used);
                // 搓 pixel
                if (
                    Game.cpu.bucket >= PIXEL_CPU_COST &&    // 逻辑短路优化
                    !settings.stopPixel &&
                    Game.cpu.generatePixel
                ) {
                    Game.cpu.generatePixel();
                    Logger.success('生产了一枚 pixel', 'BOT');
                }
            });
        };
    }

    static getCpuUsageAvg() {
        return cpuUsageTrack.sum() / cpuUsageTrack.length;
    }
    static getCpuUsageStddev() {
        const avg = this.getCpuUsageAvg();
        const sum = cpuUsageTrack.reduce((a, b) => a + Math.pow(b - avg, 2), 0);
        return Math.sqrt(sum / cpuUsageTrack.length);
    }
}